#include "StringUtil.h"
#include <unistd.h>
#include <stdlib.h>

namespace BASE{
	std::string lowerstr(const std::string & source){
		std::string str;
		for(size_t i = 0; i < source.size(); ++i){
			str[i] = tolower(source[i]);
		}
		return str;
	}

	std::string upperstr(const std::string & source){
		std::string str;
		for(size_t i = 0; i < source.size(); ++i){
			str[i] = toupper(source[i]);
		}
		return str;
	}

	Strings stringsplit(const std::string & source, const std::string & split){
		Strings strs;
		std::string src = source;
		size_t pos = src.find(split);
		std::string tmpstr;
		while(pos != std::string::npos){
			tmpstr = src.substr(0, pos);
			if (!tmpstr.empty()){
				strs.push_back(tmpstr);
			}
			src = src.substr(pos + 1);
			pos = src.find(split);
		}
		tmpstr = src.substr(pos + 1);
		if (!tmpstr.empty()){
			strs.push_back(tmpstr);
		}
		return strs;
	}

	std::string trim(std::string & source, const std::string & match ) {
		std::string result = ltrim(source, match);
		result = rtrim(source, match);
		return result;
	}

	void initMatch(uint8_t * chmap, int chmapSize, const std::string & match){
		memset(chmap, 0, chmapSize);
		uint8_t ch = 0;
		for(size_t i = 0; i < match.size(); ++i){
			ch = (uint8_t)match[i];
			chmap[ch] |= (1 << (ch & 0x07));
		}
	}

	std::string ltrim(std::string & source, const std::string & match){
		uint8_t chmap[256];
		initMatch(chmap, sizeof(chmap), match);
		size_t pos = 0;
		for (; pos < source.size(); ++pos){
			uint8_t ch = (uint8_t)source[pos];
			if ((chmap[ch] & (1 << (ch & 0x07))) == 0){
				break;
			}
		}
		if (0 != pos){
			source = source.substr(pos);
		}
		return source;
	}

	std::string rtrim(std::string & source, const std::string & match){
		uint8_t chmap[256];
		initMatch(chmap, sizeof(chmap), match);
		size_t pos = source.length() - 1;
		for (; pos > 0; --pos){
			uint8_t ch = (uint8_t)source[pos];
			if ((chmap[ch] & (1 << (ch & 0x07))) == 0){
				break;
			}
		}
		if (pos != source.length() -1 ){
			source = source.substr(0, pos + 1);
		}
		return source;
	}

	NumType getNumType(const std::string & val){
		if (val.empty()){
			return NUM_INVALID;
		}
		NumType numType = NUM_INT;
		char ch = val[0];
		if (ch == '-'){
			numType = NUM_NEG;
		}else if(val.find(".") != std::string::npos){
			numType = NUM_DOUBLE;
		}else if ('0' == ch && val.size() >= 2){
			ch = val[1];
			ch = tolower(ch);
			if (ch >= '0' && ch <= '7'){
				numType = NUM_OCT;
			}else if (ch == 'x'){
				numType = NUM_HEX;
			}else{
				numType = NUM_INVALID;
			}
		}
		return numType;
	}

	bool getBool(const std::string & val, bool defaultVal){
		if(strncasecmp(val.c_str(), "true", 4) == 0 || strncasecmp(val.c_str(), "1", 1) == 0){
			return true;
		}else if (strncasecmp(val.c_str(), "false", 5) == 0 || strncasecmp(val.c_str(), "0", 1) == 0){
			return false;
		}else{
			return defaultVal;
		}
	}

	int16_t getShort(const std::string & val){
		return (int16_t)getLong(val);
	}

	int32_t getInt(const std::string & val){
		return (int32_t)getLong(val);
	}

	double getDouble(const std::string &val){
		return atof(val.c_str());
	}

	int64_t getLong(const std::string &val){
		NumType numType = getNumType(val);
		int64_t lval = 0;
		int base = 10;
		switch(numType){
			case NUM_OCT:
				base = 8;
				break;
			case NUM_HEX:
				base = 16;
				break;
		}
		lval = strtoll(val.c_str(), NULL, base);
		return lval;
	}

}
